package com.astersoft.lib.hash;

/*
 * Copyright 2012 AsterSoft personal developer - Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Utility class for Hashing 
 * 
 * @author dario durzo
 * @version 0.1
 * @date 26-08-2009
 */
public class ASHashUtil {
	private static final MessageDigest MESSAGE_DIGEST;
	public static final String[] EMPTY_ARRAY = new String[0];

	static {
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch(NoSuchAlgorithmException err) {
			throw new IllegalStateException();
		}
		MESSAGE_DIGEST = md;
	}
	private static final String HEX_CHARS = "0123456789ABCDEF";

	/**
	 * Encodes a string with hash MD5 method
	 * 
	 * @param str String to encode
	 * @return Encoded String
	 * @throws NoSuchAlgorithmException
	 */
	public static String getMD5(String source) {    
		byte[] bytes;
		try {
			bytes = source.getBytes("UTF-8");
		} catch(java.io.UnsupportedEncodingException ue) {
			throw new IllegalStateException(ue);
		}
		byte[] result;
		synchronized(MESSAGE_DIGEST) {
			MESSAGE_DIGEST.update(bytes);
			result = MESSAGE_DIGEST.digest();
		}
		char[] resChars = new char[32];
		int len = result.length;
		for(int i = 0; i < len; i++) {
			byte b = result[i];
			int lo4 = b & 0x0F;
			int hi4 = (b & 0xF0) >> 4;
			resChars[i*2] = HEX_CHARS.charAt(hi4);
			resChars[i*2 + 1] = HEX_CHARS.charAt(lo4);
		}
		return new String(resChars);
	}

	public static String getHash32(String source) 
	throws UnsupportedEncodingException {
		String md5 = getMD5(source);
		return md5.substring(0, 8);
	}      

	public static String getHash64(String source) 
	throws UnsupportedEncodingException {
		String md5 = getMD5(source);
		return md5.substring(0, 16);
	}   
	
	/**
	 * Crypt source string with the SHA-256 algorithm
	 * 
	 * @param s - the string to crypt
	 * @return - the crypted string
	 * @throws NoSuchAlgorithmException - if algorithm is non supported
	 */
	public static String getSHA256(String s) 
			throws NoSuchAlgorithmException {
		String algorithm = "SHA-256"; // MD5
		MessageDigest d = MessageDigest.getInstance(algorithm);
		d.reset();
		d.update(s.getBytes());
		final byte[] digested = d.digest();
		final char[] hexChar = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
				'9', 'a', 'b', 'c', 'd', 'e', 'f' };
		StringBuilder l = new StringBuilder();
		for (byte b : digested) {
			l.append(hexChar[(b & 0xf0) >>> 4]);
			l.append(hexChar[b & 0x0f]);
		}
		return l.toString();
	}
	
	/**
	 * Get the hash representation of
	 * the data array
	 * 
	 * @param data
	 * @return
	 */
	public static int hash(byte[] data) {
		if (data == null || data.length == 0)
			return 0x42696C6C;
		else {
			int hash = 0;
			/*
			 * Seed the Toolbox PRNG with chartonum(char 1 of password) + the
			 * length of password
			 */
			int seed = (data[0] & 0xFF) + data.length;
			/* Loop through all the BITS of password */
			for (byte b : data) {
				for (int m = 0x80; m != 0; m >>>= 1) {
					/* Call Random() */
					long newSeed = (seed & 0xFFFFFFFFL) * 0x41A7L;
					while (newSeed >= 0x80000000L) {
						newSeed = (newSeed & 0x7FFFFFFFL) + (newSeed >>> 31L);
					}
					seed = (newSeed == 0x7FFFFFFFL) ? 0 : (int) newSeed;
					/* If the bit is set, add in the _new_ random seed */
					if ((b & m) != 0)
						hash += seed;
				}
			}
			/* Return accumulator */
			return hash;
		}
	}

	/**
	 * Test point
	 * 
	 * @param args
	 */
	public static void main(String[] args){
		try {
			System.out.println(getSHA256("The quick brown fox jumps over the lazy dog"));
			System.out.println(getMD5("The quick brown fox jumps over the lazy dog"));
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
